package network.httpserver;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;

public class RequestHandler implements Handler{

	private ChannelIO cio;
	private ByteBuffer requestBuffer;
	
	private boolean requestRecieved = false;
	private Request request = null;
	private Response response = null;
	
	public RequestHandler(ChannelIO cio) {
		this.cio = cio;
	}
	
	/**
	 * 接收HTTP请求
	 * @param key
	 * @return
	 * @throws java.io.IOException
	 */
	private boolean receive(SelectionKey key) throws IOException{
//		ByteBuffer tmp = null;
		
		if(requestRecieved) return true;	//如果接受到了HTTP请求的所有数据，就返回true
		
		if((cio.read() < 0) || 
				Request.isComplete(
						cio.getReadBuf())){
			requestBuffer = cio.getReadBuf();
			return (requestRecieved = true);
		}
		
		return false;
	}
	
	/**
	 * 解析HTTP请求中的数据，构造相应的Response对象
	 * @return
	 * @throws java.io.IOException
	 */
	private boolean parse() throws IOException{
		try{
			request = Request.parse(requestBuffer);
			return true;
		}catch(MalformedRequestException e){
			//HTTP请求格式不正确，
			response = new Response(Response.Code.BAD_REQUEST, new StringContent(e));
		}
		return false;
	}

	/**
	 * 创建HTTP响应
	 * @throws java.io.IOException
	 */
	private void build() throws IOException{
		Request.Action action = request.action();
		//仅支持get和head请求方式
		if(action != Request.Action.GET && action != Request.Action.HEAD){
			response = new Response(Response.Code.METHOD_NOT_ALLOWED, 
					new StringContent("Method Not Allowed"));
		}else{
			//正确的相应
			System.out.println("200");
			response = new Response(Response.Code.OK, new FileContent(request.uri()), action);
		}
	}
	
	private boolean send() throws IOException{
		return response.send(cio);
	}
	
	public void handle(SelectionKey key) throws IOException{
		try{
			if(request == null){
				if(!receive(key))	
					return;
				
				requestBuffer.flip();
				
				if(parse())	build();
				
				try{
					System.out.println("prepare 1");
					response.prepare();	//准备HTTP相应的内容
					System.out.println("prepare 2");
				}catch(IOException ie){
					response.release();
					response = new Response(Response.Code.NOT_FOUND, new StringContent(ie));
					response.prepare();
					ie.printStackTrace();
				}
				
				if(send()){
					//如果HTTP响应没有发送完毕，则需要注册写就绪事件
					//以便在写就绪时间发生时继续发送数据
					key.interestOps(SelectionKey.OP_WRITE);
				}else{
					//如果HTTP响应发送完毕，就断开底层连接
					//并且释放Response占用的资源
					cio.close();
					response.release();
				}
			}else{
				//HTTP相应发送完毕
				if(!send()){
					cio.close();
					response.release();
				}
			}
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}
